package com.moose.operator.util;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * <p>
 * Description
 * </p>
 *
 * @author taohua
 * @version v1.0.0
 * @date 2020 2020/3/21 16:20
 * @see com.moose.operator.util
 */
public class OkHttpClientUtils {

  private static final int READ_TIMEOUT = 100;
  private static final int CONNECT_TIMEOUT = 60;
  private static final int WRITE_TIMEOUT = 60;
  private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
  private static final byte[] LOCKER = new byte[0];
  private static OkHttpClientUtils mInstance;
  private final OkHttpClient okHttpClient;

  private OkHttpClientUtils() {
    okhttp3.OkHttpClient.Builder clientBuilder = new okhttp3.OkHttpClient.Builder();
    // 读取超时
    clientBuilder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
    // 连接超时
    clientBuilder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
    //写入超时
    clientBuilder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
    okHttpClient = clientBuilder.build();
  }

  /**
   * 单例模式获取 NetUtils
   *
   * @return {@link OkHttpClientUtils}
   */
  public static OkHttpClientUtils getInstance() {
    if (mInstance == null) {
      synchronized (LOCKER) {
        if (mInstance == null) {
          mInstance = new OkHttpClientUtils();
        }
      }
    }
    return mInstance;
  }

  /**
   * GET，同步方式，获取网络数据
   *
   * @param url 请求地址
   * @return {@link Response}
   */
  public Response getData(String url) {
    // 构造 Request
    Request.Builder builder = new Request.Builder();
    Request request = builder.get().url(url).build();
    // 将 Request 封装为 Call
    Call call = okHttpClient.newCall(request);
    // 执行 Call，得到 Response
    Response response = null;
    try {
      response = call.execute();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return response;
  }

  /**
   * POST 请求，同步方式，提交数据
   *
   * @param url        请求地址
   * @param bodyParams 请求参数
   * @return {@link Response}
   */
  public Response postData(String url, Map<String, String> bodyParams) {
    // 构造 RequestBody
    RequestBody body = setRequestBody(bodyParams);
    // 构造 Request
    Request.Builder requestBuilder = new Request.Builder();
    Request request = requestBuilder.post(body).url(url).build();
    // 将 Request 封装为 Call
    Call call = okHttpClient.newCall(request);
    // 执行 Call，得到 Response
    Response response = null;
    try {
      response = call.execute();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return response;
  }

  /**
   * GET 请求，异步方式，获取网络数据
   *
   * @param url       请求地址
   * @param myNetCall 回调函数
   */
  public void getDataAsync(String url, final MyNetCall myNetCall) {
    // 构造 Request
    Request.Builder builder = new Request.Builder();
    Request request = builder.get().url(url).build();
    // 将 Request 封装为 Call
    Call call = okHttpClient.newCall(request);
    // 执行 Call
    call.enqueue(new Callback() {

      @Override public void onResponse(Call call, Response response) throws IOException {
        myNetCall.success(call, response);
      }

      @Override public void onFailure(Call call, IOException e) {
        myNetCall.fail(call, e);
      }
    });
  }

  /**
   * POST 请求，异步方式，提交数据
   *
   * @param url        请求地址
   * @param bodyParams 请求参数
   * @param myNetCall  回调函数
   */
  public void postDataAsync(String url, Map<String, String> bodyParams, final MyNetCall myNetCall) {
    // 构造 RequestBody
    RequestBody body = setRequestBody(bodyParams);
    // 构造 Request
    buildRequest(url, myNetCall, body);
  }

  /**
   * 同步 POST 请求，使用 JSON 格式作为参数
   *
   * @param url  请求地址
   * @param json JSON 格式参数
   * @return 响应结果
   * @throws IOException 异常
   */
  public String postJson(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();
    Response response = okHttpClient.newCall(request).execute();
    if (response.isSuccessful()) {
      return response.body().string();
    } else {
      throw new IOException("Unexpected code " + response);
    }
  }

  /**
   * 异步 POST 请求，使用 JSON 格式作为参数
   *
   * @param url       请求地址
   * @param json      JSON 格式参数
   * @param myNetCall 回调函数
   * @throws IOException 异常
   */
  public void postJsonAsync(String url, String json, final MyNetCall myNetCall) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    // 构造 Request
    buildRequest(url, myNetCall, body);
  }

  /**
   * 构造 POST 请求参数
   *
   * @param bodyParams 请求参数
   * @return {@link RequestBody}
   */
  private RequestBody setRequestBody(Map<String, String> bodyParams) {
    RequestBody body = null;
    okhttp3.FormBody.Builder formEncodingBuilder = new okhttp3.FormBody.Builder();
    if (bodyParams != null) {
      Iterator<String> iterator = bodyParams.keySet().iterator();
      String key = "";
      while (iterator.hasNext()) {
        key = iterator.next();
        formEncodingBuilder.add(key, bodyParams.get(key));
      }
    }
    body = formEncodingBuilder.build();
    return body;
  }

  /**
   * 构造 Request 发起异步请求
   *
   * @param url       请求地址
   * @param myNetCall 回调函数
   * @param body      {@link RequestBody}
   */
  private void buildRequest(String url, final MyNetCall myNetCall, RequestBody body) {
    Request.Builder requestBuilder = new Request.Builder();
    Request request = requestBuilder.post(body).url(url).build();
    // 将 Request 封装为 Call
    Call call = okHttpClient.newCall(request);
    // 执行 Call
    call.enqueue(new Callback() {
      @Override public void onResponse(Call call, Response response) throws IOException {
        myNetCall.success(call, response);
      }

      @Override public void onFailure(Call call, IOException e) {
        myNetCall.fail(call, e);
      }
    });
  }

  /**
   * 自定义网络回调接口
   */
  public interface MyNetCall {
    /**
     * 请求成功的回调处理
     *
     * @param call     {@link Call}
     * @param response {@link Response}
     * @throws IOException 异常
     */
    void success(Call call, Response response) throws IOException;

    /**
     * 请求失败的回调处理
     *
     * @param call {@link Call}
     * @param e    异常
     */
    void fail(Call call, IOException e);
  }
}

